
"""Serves as the driver for events in the simulation"""

_simulation = None
_singleton = "DO NOT USE THIS VARIABLE OUTSIDE THIS MODULE"



EVENTS = 5 #The rank at which world events and actions occur
UPDATES = 10 #The rank at which model updates occur
UI = 15 #The rank that UI updates occur


def get_simulation():
    global _simulation, _singleton
    if not _simulation:
        _simulation = Simulation(_singleton)
    return _simulation

class Simulation:
    """Singleton class that unifies all aspects of the simulation"""
    
    def __init__(self, code = None):
        """
        code - Dummy arguement that prevents this constructor from being used
               outside of this module, do not attempt to provide a valid code.
        """
        if code != _singleton:
            raise Exception("instantiating singleton class not permitted by " +
                            "outside 'get_simulation'")
            
        self.world = None
        self._turn_listeners = []
        
    def add_turn_listener(self, listener, rank):
        """
        Adds a listener to the engine. The listeners will be notified in order
        from lowest to highest ranks, and will be executed randomly as compared
        to other listeners of the same rank
        
        One listener can be added several times at different ranks, and will be
        notified accordingly.
        
        listener - The listener to add (must define the do_turn(rank)) funciton
        rank - The rank of this listener as compared to other listeners
        """
        while len(self._turn_listeners) < rank + 1:
            self._turn_listeners.append(set())
        
        self._turn_listeners[rank].add(listener)
        
    def remove_turn_listener(self, listener, rank = -1):
        if rank < -1:
            for rank in self._turn_listeners:
                rank.remove(listener)
        else:
            self._turn_listeners[rank].remove(listener)
            
    def clear_listeners(self):
        self._turn_listeners = []
        
    
    def do_turn(self):
        for rank in range(len(self._turn_listeners)):
            listeners = self._turn_listeners[rank]
            for listener in listeners:
                listener.do_turn(rank)
            
    
        
        